package cuckoo.aop;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cuckoo.aop.config.ProxyBeanListener;
import cuckoo.aop.intercept.Interceptor;
import cuckoo.ioc.factory.DefaultBeanFactory;

public class ProxyBeanFactory extends DefaultBeanFactory {
	private List<ProxyBeanListener> listeners = new ArrayList<ProxyBeanListener>();

	private Map<Method, Set<Interceptor>> interceptMap = new HashMap<Method, Set<Interceptor>>();

	@Override
	protected Object postBeanProcessor(Object bean) {
		Class<?> clazz = bean.getClass();

		if (clazz.getInterfaces().length == 0 || !isProxy(clazz)) {
			return bean;
		}

		return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), clazz.getInterfaces(),
				new ProxyHandler(interceptMap, bean));

	}

	private boolean isProxy(Class<?> clazz) {
		boolean ret = false;
		Method[] methods = clazz.getMethods();
		for (Method m : methods) {
			for (ProxyBeanListener listener : listeners) {
				Interceptor interceptor = listener.intercept(m);
				if (interceptor != null) {
					addCache(m, interceptor);
					ret = true;
				}
			}
		}
		return ret;
	}

	private void addCache(Method m, Interceptor interceptor) {
		Set<Interceptor> set = interceptMap.get(m);
		if (set == null) {
			set = new HashSet<Interceptor>();
			interceptMap.put(m, set);
		}

		set.add(interceptor);
	}

	public void addListener(ProxyBeanListener listener) {
		listeners.add(listener);
	}
}
